package parknfly

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"parking-lot-go-push/logger"
	"parking-lot-go-push/model"
	"parking-lot-go-push/model/config"
	"strings"
	"time"
)

var parknflyPushLogger = logger.NewLogger("parknfly", "push")

// 回参格式
type ResponseData struct {
	Code   string      `json:"code"`
	Msg    string      `json:"msg"`
	Status int         `json:"status"`
	Data   interface{} `json:"data"`
}

// 签名
type ParknflySigner struct {
	Secretkey string                 `json:"-"`
	Appid     string                 `json:"appid"`
	Rand      int                    `json:"rand"`
	Signature string                 `json:"sign"`
	Data      map[string]interface{} `json:"data"`
}

func NewSigner() *ParknflySigner {

	var configParknflyData config.ConfigParknflyStruct
	model.GetModelDataFirst(
		model.Db,
		configParknflyData.TableName(),
		&configParknflyData,
		model.QueryOptions{
			Conditions: map[string]interface{}{
				"status": 1,
			},
		})

	//配置信息
	return &ParknflySigner{
		Secretkey: configParknflyData.Secretkey,
		Appid:     configParknflyData.Appid,
	}
}

// 生成签名
func (s *ParknflySigner) GenerateSign(data map[string]interface{}) (string, error) {
	jsonData, err := json.Marshal(data)
	if err != nil {
		parknflyPushLogger.Error(fmt.Sprintf("生成签名转换json失败,错误:%s", err.Error()))
		return "", errors.New("转换json失败")
	}

	jsonDataStr := strings.ReplaceAll(string(jsonData), "/", `\/`)

	var signatureString string
	//签名字符串
	if len(data) == 0 {
		signatureString = fmt.Sprintf("appid=%s&rand=%d&secretkey=%s", s.Appid, s.Rand, s.Secretkey)
	} else {
		signatureString = fmt.Sprintf("appid=%s&data=%s&rand=%d&secretkey=%s", s.Appid, jsonDataStr, s.Rand, s.Secretkey)
	}

	parknflyPushLogger.Info(fmt.Sprintf("签名串:%s", signatureString))

	hasher := md5.New()
	hasher.Write([]byte(signatureString))
	signature := hex.EncodeToString(hasher.Sum(nil))

	// 将签名转换为大写形式
	signature = strings.ToUpper(signature)
	return signature, nil
}

// curl post json 请求
func (s *ParknflySigner) CurlPostJson(method string, data map[string]interface{}) (err error, returnData ResponseData) {

	var configParknflyData config.ConfigParknflyStruct
	model.GetModelDataFirst(
		model.Db,
		configParknflyData.TableName(),
		&configParknflyData,
		model.QueryOptions{
			Conditions: map[string]interface{}{
				"status": 1,
			},
		})

	//请求地址拼接
	url := configParknflyData.PushBaseUrl
	parknflyPushLogger.Info(fmt.Sprintf("推送接口:%s", url))
	parknflyPushLogger.Info(fmt.Sprintf("推送方法:%s", method))

	currentTime := time.Now()
	millisecondTimestamp := currentTime.UnixNano() / int64(time.Millisecond)
	millisecondTimestampInt := int(millisecondTimestamp)
	s.Rand = millisecondTimestampInt

	sign, err := s.GenerateSign(data)
	if err != nil {
		parknflyPushLogger.Error(fmt.Sprintf("生成签名失败:%s", err.Error()))
		parknflyPushLogger.Error(data)
		return errors.New("生成签名失败"), returnData
	}

	// 将 JSON 数据封装为请求体
	jsonData := map[string]interface{}{
		"appid":  s.Appid,
		"method": method,
		"rand":   millisecondTimestamp,
		"sign":   sign,
	}

	if len(data) != 0 {
		jsonData["data"] = data
	}

	jsonBytes, err := json.Marshal(jsonData)
	parknflyPushLogger.Info(fmt.Sprintf("推送参数:%s", jsonBytes))
	if err != nil {
		parknflyPushLogger.Error(fmt.Sprintf("转换json失败:%s", err.Error()))
		parknflyPushLogger.Error(jsonData)
		return errors.New("转换json失败"), returnData
	}

	// 创建自定义的 HTTP 客户端
	client := &http.Client{}

	// 创建 POST 请求
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes))
	if err != nil {
		parknflyPushLogger.Error(fmt.Sprintf("创建请求失败:%s", err.Error()))
		return errors.New("创建请求失败"), returnData
	}

	// 发起请求
	response, err := client.Do(req)

	if err != nil {
		parknflyPushLogger.Error(fmt.Sprintf("请求失败:%s", err.Error()))
		return errors.New("请求失败"), returnData
	}

	defer response.Body.Close()

	// 读取响应内容
	responseBody, err := io.ReadAll(response.Body)
	if err != nil {
		parknflyPushLogger.Error(fmt.Sprintf("获取响应内容失败:%s", err.Error()))
		return errors.New("获取响应内容失败"), returnData
	}

	parknflyPushLogger.Info("---- 接收泊安飞反馈 ----")
	parknflyPushLogger.Info(fmt.Sprintf("responseData:%s", string(responseBody)))

	var responseData ResponseData
	if err := json.Unmarshal(responseBody, &responseData); err != nil {
		parknflyPushLogger.Error(fmt.Sprintf("解析响应结果失败:%s", err.Error()))
		return errors.New("解析响应结果失败"), returnData
	}

	if responseData.Code == "0" && responseData.Status == 1 {
		return nil, responseData
	}

	return errors.New(responseData.Msg), returnData
}
